/*
* License:  This  program  is  free  software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the  Free Software Foundation; either version 3 of the License, or (at your
* option)  any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*/

package pcgen.CharacterViewer;

import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import pcgen.android.app.AppUtils;
import pcgen.android.Logger;
import pcgen.android.app.DialogClickListenerHandler;

import pcgen.CharacterViewer.R;
import pcgen.CharacterViewer.resources.GameFolder;
import pcgen.CharacterViewer.resources.GameResource;
import pcgen.CharacterViewer.resources.GameResource.ResourceTypes;
import pcgen.CharacterViewer.resources.GameResourceLoadException;

public class CharacterViewerActivity extends AppActivity 
{
	public void removeResource(GameResource resource)
	{
		gameResourceRemove(resource);
		setup();
	}
	
	@Override
    protected boolean handleOptionsItemSelected(MenuItem item)
	{
		try
		{
			if (item.getItemId() == R.id.menu_game_close)
			{
				gameFolderCloseConfirm();
				return true;
			}
			else if (item.getItemId() == R.id.menu_game_new)
			{
				gameFolderCreate();
				return true;
			}
			else if (item.getItemId() == R.id.menu_game_open)
			{
				gameFolderSelect();
				return true;
			}
			else if (item.getItemId() == R.id.menu_game_add_character)
			{
				gameResourceSelect(true);
				return true;
			}
			else if (item.getItemId() == R.id.menu_game_add_resource)
			{
				gameResourceSelect(false);
				return true;
			}
			
			_interface.handleOptionsItemSelected(item);
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "handleOptionsItemSelected", tr);
		}
		
		return false;
	}

    @Override
    protected void initialize(Bundle savedInstanceState)
    {
    	try
    	{
	    	super.initialize(savedInstanceState);
	    	
	    	int currentapiVersion = android.os.Build.VERSION.SDK_INT;
	    	if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB)
	    		_interface = new ResourceWidgetDefault(R.id.fragment_content);
	    	else
	    		_interface = new ResourceWidgetPrevious(R.id.fragment_content);
	    	
	    	_interface.initialize(this);
	    	_interface.toggleOn();

	        // first, show the welcome if it hasn't been shown already:
	        final SharedPreferences preferences = getPreferences();
	        if (!preferences.getBoolean(PREFERENCE_EULA_ACCEPTED, false) && !_welcomeShown) 
	        {
	        	AppUtils.alertOkCancelWithAsset(this, String.format(getString(R.string.dialog_title_welcome), getString(R.string.app_name)), "welcome.html", 
		            new DialogClickListenerHandler(this) 
	    			{           
	    				public void onClick(DialogInterface dialog, int id) 
	    				{               
	    		            preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true).commit();
	    		            initializeEx();
						}       
	    			},
	    			new DialogClickListenerHandler(this) 
	    			{           
	    				public void onClick(DialogInterface dialog, int id) 
	    				{
	    					AppUtils.confirm((Activity)_context, R.string.confirm_acceptance,
	    						new DialogClickListenerHandler((Activity)_context) 
		    	    			{           
		    	    				public void onClick(DialogInterface dialog, int id) 
		    	    				{               
		    	    		            finish();
		    						}       
		    	    			});          
						}       
	    			});
	        	
	        	return;
	        }
	        
            initializeEx();
    	}
		catch (Throwable tr)
		{
			Logger.e(TAG, "initialize", tr);
		}
    }
	
	protected void initializePre()
    {
		//if (android.os.Build.VERSION.SDK_INT < 11) 
		//	setTheme(R.style.Theme_Sherlock);
    }

    @Override
    protected void initializeActivityResult(int requestCode, int resultCode, Intent data) 
    {
    	try
    	{
	        super.initializeActivityResult(requestCode, resultCode, data);
	        
	        switch (requestCode) 
	        {
		        case GAME_RESOURCE_SELECT:
		            if ((resultCode == RESULT_OK) && (data != null)) 
		            {
		            	try
		            	{
			            	String type = data.getExtras().getString(SelectGameResourceDialogActivity.RESULT_RESOURCE_TYPE);
			            	GameResource.ResourceTypes resourceType = GameResource.ResourceTypes.valueOf(type);
			            	String name = data.getStringExtra(SelectGameResourceDialogActivity.RESULT_NAME);
			            	String location = data.getStringExtra(SelectGameResourceDialogActivity.RESULT_PATH);
			            	
			            	gameResourceAdd(name, location, resourceType);
		            	}
		            	catch (GameResourceLoadException grlex)
		            	{
		            		Toast.makeText(this, this.getString(R.string.dialog_validation_select_game_invalid_data), Toast.LENGTH_SHORT).show();
		            	}
		            }
		            break;
	        }
    	}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "initializeActivityResult", tr);
    	}
    }

	@Override
	protected void initializeContentView()
	{
		setContentView(R.layout.main);
	}
	
	protected void initializeEx()
	{
		try
		{
			setup();
			
			GameFolder folder = getApplicationApp().getGameFolder();
			if (folder != null)
			{
				gameInit();
				return;
			}
			
			String name = getPreferences().getString(PREFERENCE_CURRENT_GAME, "");
			if (!StringUtils.isEmpty(name))
				gameFolderOpen(name);
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "initializeEx", tr);
		}
	}
    
	@Override
	protected void initializeOptionMenus(Menu menu)
	{
		try
		{
			super.initializeOptionMenus(menu);
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "initializeOptionMenus", tr);
		}
	}
    
	@Override
	protected void initializeOptionMenusCompleted(Menu menu)
	{
		try
		{
			super.initializeOptionMenusCompleted(menu);
			
			setupMenu();
		}
		catch (Throwable tr)
		{
			Logger.e(TAG, "initializeOptionMenusCompleted", tr);
		}
	}
	
	@Override
	protected Dialog onCreateDialog(int id) 
	{
		try
		{
			super.onCreateDialog(id);
			
		    switch (id) 
		    {
			    case DIALOG_GAME_NAME:
			    	final Activity reference = this;
			        
			    	final Dialog dialogNewGame = new Dialog(this);
			        dialogNewGame.setTitle(getString(R.string.dialog_title_new_game));
			    	dialogNewGame.setContentView(R.layout.dialog_request_name);	
			    	
			    	final TextView gameName = (TextView)dialogNewGame.findViewById(R.id.dialog_request_input_name);
			    	
			    	final GameTypes.GameFolderTypeList listGameTypes = getApplicationApp().getGameTypes().getTypes();
			    	
			        ArrayList<String> items = new ArrayList<String>();
			        items.addAll(listGameTypes.values());
			        Collections.sort(items);
			        
			        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, items);
			        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
			        
			        final Spinner gameType = (Spinner)dialogNewGame.findViewById(R.id.dialog_request_input_game_type);
			    	gameType.setAdapter(adapter);
			        
			        Button buttonOk = (Button)dialogNewGame.findViewById(R.id.button_ok);
			        buttonOk.setOnClickListener(
			        	new OnClickListener() 
			        	{
				            public void onClick(View view) 
							{
			                    final String name = gameName.getText().toString();
			                    if (StringUtils.isEmpty(name))
			                    {
			                    	Toast.makeText(reference, String.format(reference.getString(R.string.validation_required), reference.getString(R.string.dialog_validation_new_game_name)), Toast.LENGTH_SHORT).show();
			                    	return;
			                    }
			                    
			                    if (!getApplicationApp().validateNameCharacters(name))
			                    {
			                    	Toast.makeText(reference, reference.getString(R.string.validation_name_invalid_characters), Toast.LENGTH_SHORT).show();
			                    	return;
			                    }
			                    
			                    if (gameFolderCheckExistingName(name))
			                    {
			                    	//Toast.makeText(reference, String.format(reference.getString(R.string.dialog_validation_new_game_input_exists), reference.getString(R.string.dialog_title_new_game)), Toast.LENGTH_SHORT).show();
			                    	//return;
			                    	
			                    	AppUtils.alertOkCancel(reference, getString(R.string.dialog_title_select_game_resource), getString(R.string.dialog_text_game_confirm_overwrite),
			                				new DialogClickListenerHandler(reference) 
			                				{           
			                					public void onClick(DialogInterface dialog, int id) 
			                					{
			                						onValidGameName(reference, dialogNewGame, name, gameType, listGameTypes);
			                					}
			                				}, 
			                				null);
			                    	return;
			                    }
			                    
			                    onValidGameName(reference, dialogNewGame, name, gameType, listGameTypes);
							}
				        });
			        Button buttonCancel = (Button)dialogNewGame.findViewById(R.id.button_cancel);
			        buttonCancel.setOnClickListener(
		        		new OnClickListener() 
			        	{
				            public void onClick(View view) 
							{
								dialogNewGame.dismiss();
							}
				        });
			        dialogNewGame.show();
			        break;
		    }
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "onCreateDialog", tr);
    	}
	    
	    return null;
	}
	
	protected void onValidGameName(Activity reference, DialogInterface dialog, String name, Spinner gameType, GameTypes.GameFolderTypeList listGameTypes)
	{
		try
		{
			String type = "";
            String gameTypeSelected = (String)gameType.getSelectedItem();
            for (Map.Entry<String, String> entry : listGameTypes.entrySet()) 
            {
            	if (!entry.getValue().equalsIgnoreCase(gameTypeSelected))
            		continue;
            	
            	type = entry.getKey();
            	break;
            }
            
            if (StringUtils.isEmpty(type))
            {
            	Toast.makeText(reference, String.format(reference.getString(R.string.validation_required), reference.getString(R.string.dialog_validation_new_game_type)), Toast.LENGTH_SHORT).show();
            	return;
            }
            
            //GameFolder folder = new GameFolder(type, name);
            GameFolder folder = GameFolder.newInstance(this, type, name);
            getApplicationApp().setGameFolder(folder);
			gameFolderSave(folder);
	        getPreferences().edit().putString(PREFERENCE_CURRENT_GAME, folder.getFileName()).commit();
			gameInit();
			
			dialog.dismiss();
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "onValidGameName", tr);
    	}
	}

	protected void stateRestore(Bundle inState)
	{
		try
		{
			_stateActivity = StatesActivity.valueOf(inState.getString(KEY_STATE));
			GameFolder folder = (GameFolder)inState.getParcelable(KEY_GAME_FOLDER);
			getApplicationApp().setGameFolder(folder);
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "stateRestore", tr);
    	}
	}
	
	protected void stateSave(Bundle outState)
	{
		try
		{
			gameFolderSave();
			outState.putString(KEY_STATE, _stateActivity.toString());
			outState.putParcelable(KEY_GAME_FOLDER, getApplicationApp().getGameFolder());
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "stateSave", tr);
    	}
	}

	private void gameFolderClose(boolean removeOnly)
    {
    	try
    	{
    		if (!removeOnly)
    		{
	    		GameFolder folder = getApplicationApp().getGameFolder();
	    		if (folder != null)
	    			gameFolderSave(folder);
    		}
            getApplicationApp().removeGameFolder();
            setTitle("");
            
            _interface.removeAll();
            
            _stateActivity = StatesActivity.Close;
            setup();

	        getPreferences().edit().remove(PREFERENCE_CURRENT_GAME).commit();
    	}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameFolderClose", tr);
    	}
    }

	private void gameFolderCloseConfirm()
    {
    	try
    	{
    		AppUtils.confirm(this, getString(R.string.confirm_acceptance), 
	    		new DialogClickListenerHandler(this) 
	    		{
	                public void onClick(DialogInterface dialog, int whichButton) 
	                {
	                    if (whichButton != AppUtils.ID_ALERT_POSITIVE)
	                    	return;
	                    
	                    gameFolderClose(false);
	                }
	            });
    	}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameFolderCloseConfirm", tr);
    	}
    }

	private void gameFolderCreate()
    {
    	try
    	{
    		showDialog(DIALOG_GAME_NAME);
    	}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameFolderCreate", tr);
    	}
    }
	
	private boolean gameFolderCheckExistingName(String name)
	{
		try 
		{
			name = gameFolderFileName(name);
			String[] files = getGameFileList();
			for (int i = 0; i < files.length; i++)
			{
				if (files[i].equalsIgnoreCase(name))
					return true;
			}
		} 
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameFolderCheckExistingName", tr);
    	}
		
		return false;
	}
	
	private String gameFolderFileName(String filename)
	{
		if (StringUtils.isEmpty(filename))
			return filename;
		
		if (filename.endsWith(EXTENSION_GAME))
			return filename;
		
		return filename + EXTENSION_GAME;
	}
	
	private String gameFolderNameStripExtensions(String filename)
	{
		if (StringUtils.isEmpty(filename))
			return filename;
		
		if (!filename.endsWith(EXTENSION_GAME))
			return filename;
		
		return filename.replace(EXTENSION_GAME, "");
	}
	
	private void gameFolderOpen(String filename)
	{
		try
		{
			try
			{
				GameFolder folder = new GameFolder();
				folder.load(openGameForInput(filename), true);
				String type = folder.getType();
				String name = folder.getName();
				
				folder = GameFolder.newInstance(this, type, name);
				if (folder == null)
					throw new Exception("Invalid game folder type.");
				
				folder.load(openGameForInput(filename));
				getApplicationApp().setGameFolder(folder);
				getPreferences().edit().putString(PREFERENCE_CURRENT_GAME, folder.getFileName()).commit();
			}
			catch (FileNotFoundException fnfex)
			{
				gameFolderClose(true);
				return;
			}
            
            gameInit();
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameFolderOpen", tr);
    	}
	}
	
	public void gameFolderSave()
	{
		gameFolderSave(getApplicationApp().getGameFolder());
	}
	
	private void gameFolderSave(GameFolder folder)
	{
		try
    	{
			if (folder == null)
				return;
			
			folder.save(openGameForOutput(folder.getFileName()));
    	}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameFolderSave", tr);
    	}
	}
	
	private void gameFolderSelect()
	{
		try
		{
			ArrayList<CharSequence> gameFolders = new ArrayList<CharSequence>();
			String[] fileList = getGameFileList();
			for (int i = 0; i < fileList.length; i++)
			{
				if (!fileList[i].endsWith(EXTENSION_GAME))
					continue;
				
				gameFolders.add(gameFolderNameStripExtensions(fileList[i]));
			}
			final CharSequence items[] = gameFolders.toArray(new CharSequence[gameFolders.size()]);
			
			AlertDialog.Builder builder = new AlertDialog.Builder(this)
	            .setSingleChoiceItems(items, -1,
                    new DialogInterface.OnClickListener() 
	            	{
                        public void onClick(DialogInterface dialog, int item) 
                        {
                        	_gameFolderSelectedItem = item;
                        }
                   });
			
			AppUtils.alertOkCancel(this, builder, getString(R.string.dialog_title_select_game_resource),
				new DialogClickListenerHandler(this) 
				{           
					public void onClick(DialogInterface dialog, int id) 
					{
						if (_gameFolderSelectedItem > -1)
							gameFolderOpen(items[_gameFolderSelectedItem].toString());
					}       
				}, 
				null);
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameFolderSelect", tr);
    	}
	}
	
	private void gameInit()
	{
		try
		{
			GameFolder folder = getApplicationApp().getGameFolder();
            setTitle(folder.getName());
            
            _stateActivity = StatesActivity.Open;
			setup();
            
			for (GameResource resource : folder.getResources())
				gameResourceInit(resource);
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameInit", tr);
    	}
	}
	
	private void gameResourceAdd(String name, String location, GameResource.ResourceTypes type) 
		throws Throwable
	{
		try
		{
			GameFolder folder = getApplicationApp().getGameFolder();
			
			if (folder.hasResource(name, type))
            {
            	Toast.makeText(this, getString(R.string.validation_resource_add_name_exists), Toast.LENGTH_SHORT).show();
            	return;
            }
			
			GameResource resource = folder.addResource(name, location, type);
			if (type == ResourceTypes.Character)
			{
				if (resource == null)
				{
		            Toast.makeText(this, getString(R.string.validation_resource_character_invalid_type), Toast.LENGTH_SHORT).show();
					return;
				}
			}
			folder.addResource(resource);
			gameFolderSave(folder);
			gameResourceInit(resource);
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameResourceAdd", tr);
    		throw tr;
    	}
	}
	
	private void gameResourceInit(GameResource resource)
	{
		try
		{
			if (resource.getType() == GameResource.ResourceTypes.Character)
				_interface.addResourceCharacter(resource);
			else
				_interface.addResource(resource);
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameResourceInit", tr);
    	}
	}
	
    private void gameResourceRemove(GameResource resource)
    {
    	if (resource == null)
    		return;
    	
    	GameFolder folder = getApplicationApp().getGameFolder();
		folder.removeResource(resource);
		gameFolderSave();
		
		_interface.removeResource(resource);
    }
	
	private void gameResourceSelect(boolean selectCharacter)
	{
		try
		{
			if (selectCharacter)
			{
				Intent intent = new Intent(getBaseContext(), SelectGameResourceDialogActivity.class);
				intent.putExtra(SelectGameResourceDialogActivity.SETTING_START_PATH, "/sdcard");
				intent.putExtra(SelectGameResourceDialogActivity.SETTING_SELECTION_MODE, SelectGameResourceDialogActivity.ModesSelection.Character.toString());
				startActivityForResult(intent, GAME_RESOURCE_SELECT);
			}
			else
			{
				Intent intent = new Intent(getBaseContext(), SelectGameResourceDialogActivity.class);
				intent.putExtra(SelectGameResourceDialogActivity.SETTING_START_PATH, "/sdcard");
				intent.putExtra(SelectGameResourceDialogActivity.SETTING_SELECTION_MODE, SelectGameResourceDialogActivity.ModesSelection.Other.toString());
				startActivityForResult(intent, GAME_RESOURCE_SELECT);
			}
		}
    	catch(Throwable tr)
    	{
    		Logger.e(TAG, "gameResourceSelect", tr);
    	}
	}
	
	private String[] getGameFileList() 
		throws Throwable
	{
		return getExternalFileList(FOLDER_GAME);
	}
	
	private InputStream openGameForInput(String filename) 
		throws Throwable
	{
		return openExternalFileInputApplication(gameFolderFileName(filename), FOLDER_GAME);
	}
	
	private OutputStream openGameForOutput(String filename) 
		throws Throwable
	{
		if (StringUtils.isEmpty(filename))
			return null;
		
		return openExternalFileOutputApplication(gameFolderFileName(filename), FOLDER_GAME);
	}
	
	private void setup()
	{
		TextView text = (TextView)findViewById(R.id.text_game_help);
		
		int textId = R.string.blank;
		if (_stateActivity == StatesActivity.Close)
			textId = R.string.help_game_closed;
		else if (_stateActivity == StatesActivity.Open)
			textId = R.string.help_game_opened;
		
		text.setText(textId);
		
		setupMenu();
	}
    
    private void setupMenu()
    {
    	try
    	{
    		if (getOptionMenu() == null)
    			return;
    		
	    	MenuItem itemGameClose = getOptionMenu().findItem(R.id.menu_game_close);
    		MenuItem itemGameNew = getOptionMenu().findItem(R.id.menu_game_new);
    		MenuItem itemGameOpen = getOptionMenu().findItem(R.id.menu_game_open);
    		MenuItem itemGameOpenCharacter = getOptionMenu().findItem(R.id.menu_game_add_character);
    		MenuItem itemGameOpenResource = getOptionMenu().findItem(R.id.menu_game_add_resource);
    		
    		if (_stateActivity == StatesActivity.Close)
    		{
    			itemGameClose.setVisible(false);
    			itemGameNew.setVisible(true);
    			itemGameOpen.setVisible(true);
    			itemGameOpenCharacter.setVisible(false);
    			itemGameOpenResource.setVisible(false);
    		}
    		else if (_stateActivity == StatesActivity.Open)
    		{
    			itemGameClose.setVisible(true);
    			itemGameNew.setVisible(false);
    			itemGameOpen.setVisible(false);
    			itemGameOpenCharacter.setVisible(true);
    			itemGameOpenResource.setVisible(true);
    		}
    	}
		catch (Throwable tr)
		{
			Logger.e(TAG, "setupMenu", tr);
		}
    }
    
    private IResourceWidget _interface;
    
    public enum StatesActivity
    {
    	Close,
    	Open
    }
    
	private int _gameFolderSelectedItem = -1;
    private StatesActivity _stateActivity = StatesActivity.Close;
	private boolean _welcomeShown = false;

	private final static int DIALOG_GAME_NAME = 1;

	private final static String FOLDER_GAME = "games";
	private final static String EXTENSION_GAME = ".game";

	private final static String KEY_GAME_FOLDER = "KeyGameFolder";
	private final static String KEY_STATE = "KeyState";

    private static final String PREFERENCE_CURRENT_GAME = "game.current";
	private static final String PREFERENCE_EULA_ACCEPTED = "eula.accepted";

    private static final int GAME_RESOURCE_SELECT = 1;

	private static final String TAG = CharacterViewerActivity.class.getSimpleName();
}